package com.tdd.provider;

import com.tdd.common.JSONSerializer;
import com.tdd.common.RpcDecoder;
import com.tdd.common.RpcRequest;
import com.tdd.zk.ServiceRegistry;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * @author tudedong
 * @description
 * @date 2020-06-06 20:23:58
 */
@Component
public class NettyServer implements InitializingBean,ApplicationContextAware {

    private ApplicationContext applicationContext;

    private static List<String> HOSTS = Arrays.asList("127.0.0.1");
    private static List<Integer> POSTS = Arrays.asList(8998);

    /**
     * 对外暴露的启动方法
     * @param hostname
     * @param port
     */
    public void startServer(String hostname,int port){
        startServer0(hostname,port);
    }

    /**
     * 完成对nettyserver的初始化和启动
     * @param hostname
     * @param port
     */
    private void startServer0(String hostname,int port){
        //1.创建两个线程池对象
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        try{
            //2.创建服务端的启动引导对象
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            //3.配置启动引导对象
            serverBootstrap.group(bossGroup,workGroup)
                    //设置通道为nio
                    .channel(NioServerSocketChannel.class)
                    //创建监听channel
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                            //获取管道对象
                            ChannelPipeline pipeline = nioSocketChannel.pipeline();
                            //给管道对象pipeline 设置编码
                            //对返回给客户端的数据进行编码，这里返回“success”
                            pipeline.addLast(new StringEncoder());
                            //对客户端传递过来的请求对象数据进行解码
                            pipeline.addLast(new RpcDecoder(RpcRequest.class, new JSONSerializer()));
                            //把我们自定义的channelHandler添加到管道中
                            pipeline.addLast(new UserServiceHandler(applicationContext));

                        }
                    });
            System.out.println("["+hostname+":"+port+"]服务端已启动。。。");
            //4.绑定端口
            serverBootstrap.bind(hostname,port).sync();

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //bossGroup.shutdownGracefully();
            //workGroup.shutdownGracefully();
        }

    }

    public void afterPropertiesSet() throws Exception {

        ServiceRegistry serviceRegistry = new ServiceRegistry();
        for(int i=0;i<HOSTS.size();i++){
            startServer(HOSTS.get(i),POSTS.get(i));
            //注册到zookeeper中
            serviceRegistry.register(HOSTS.get(i)+":"+POSTS.get(i));
        }
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
